import ctypes
from ctypes import c_int, c_byte, c_uint, create_string_buffer, byref, Structure
from datetime import datetime

class TSystemFileInfo(Structure):
    """OBU系统信息结构体"""
    _fields_ = [
        ('Provider', c_byte * 8),
        ('Type', c_byte),
        ('Version', c_byte),
        ('SerialNumber', c_byte * 8),
        ('SignedDate', c_byte * 4),
        ('ExpiredDate', c_byte * 4),
        ('TearFlag', c_byte)
    ]

class TVehicleFileInfo(Structure):
    """车辆信息结构体"""
    _fields_ = [
        ('LicencePlateNumber', c_byte * 12),
        ('LicencePlateColor', c_byte * 2),
        ('Class', c_byte),
        ('UserType', c_byte),
        ('Length', c_byte * 2),
        ('Width', c_byte),
        ('Heigth', c_byte),
        ('Wheels', c_byte),
        ('Axles', c_byte),
        ('WheelBases', c_byte * 2),
        ('WeitghtLimits', c_byte * 3),
        ('SpecificInfomation', c_byte * 16),
        ('EngineNumber', c_byte * 16)
    ]

class T0015FileInfo(Structure):
    """0015文件结构体"""
    _fields_ = [
        ('Provider', c_byte * 8),
        ('CardType', c_byte),
        ('CardVersion', c_byte),
        ('Network', c_byte * 2),
        ('CardID', c_byte * 8),
        ('SignedDate', c_byte * 4),
        ('ExpiredDate', c_byte * 4),
        ('LicencePlateNumber', c_byte * 12),
        ('UserType', c_byte),
        ('PlateColor', c_byte * 2)
    ]

class M600t:
    """M600t读写器Python封装类"""
    CALL_TIMEOUT = 3000
    ESAM_CHANNEL = 2
    ICC_CHANNEL = 1
    
    def __init__(self):
        """初始化M600t实例"""
        try:
            self.dll = ctypes.WinDLL("gv_rsu_icc_api.dll")
            self._setup_functions()
        except OSError as e:
            if "is not a valid Win32 application" in str(e):
                raise RuntimeError("请使用32位Python解释器加载32位DLL")
            raise
        
        self.iM600tFD = 0
        self.strRsuID = ""
        self.strRsuVer = ""
        self.gSYSTEMINFO = ""
        self.Is3Des = True
        self.g_lIsZeroKey = 0
        self.ProCardKeyType = 0
        self.PurchasePsamSlot = 0
        self.bIsPurchse = True
        self.g_CardIDFromDSRC = ""
        self.chPaySerial = 0

    def _setup_functions(self):
        """设置DLL函数原型"""
        # RSU_Open
        self.RSU_Open = self.dll.RSU_Open
        self.RSU_Open.argtypes = [c_int, ctypes.c_char_p, c_int]
        self.RSU_Open.restype = c_int
        
        # RSU_Close
        self.RSU_Close = self.dll.RSU_Close
        self.RSU_Close.argtypes = [c_int]
        self.RSU_Close.restype = c_int
        
        # 其他函数原型设置...
        # 根据实际需要添加更多函数原型

    def InitRSUDevice(self, m_fd, iChannelId, BSTInterval, BSTRetryInterval, TXPower, RSUInfo):
        """初始化RSU设备"""
        ret = -1
        RSUStatus = c_int(-1)
        strUnixTime = create_string_buffer(32)
        UnixDate = int((datetime.utcnow() - datetime(1970,1,1)).total_seconds())
        
        strUnixTime.value = str(UnixDate).encode()
        
        for i in range(3):
            ret = self.RSU_Open(m_fd, strUnixTime, BSTInterval)
            rlen = c_int(0)
            ret = self.RSU_INIT_rs(m_fd, byref(RSUStatus), byref(rlen), RSUInfo, 1000)
            if ret == 0:
                self.strRsuID = self._bytes_to_hex(RSUInfo[:4])
                self.strRsuVer = self._bytes_to_hex(RSUInfo[4:6])
                break
        return ret == 0

    def ConnectObu(self, iMfd):
        """发送BST连接OBU"""
        ret = 0
        ReturnStatus = c_int(0)
        Profile = c_int(0)
        ApplicationList = c_int(0)
        Application = (c_byte * 1000)()
        ObuConfiguration = (c_byte * 1000)()
        
        strUnixTime = create_string_buffer(32)
        UnixDate = int((datetime.utcnow() - datetime(1970,1,1)).total_seconds())
        strUnixTime.value = str(UnixDate).encode()
        
        RSUID = (c_byte * 4)()
        timebuf = (c_byte * 4)()
        found = 0
        
        for cnt in range(3):
            if iMfd == 0:
                break
                
            timebuf[0] = (UnixDate >> 24) & 0xFF
            timebuf[1] = (UnixDate >> 16) & 0xFF
            timebuf[2] = (UnixDate >> 8) & 0xFF
            timebuf[3] = UnixDate & 0xFF

            RSUID[0] = 0xA0
            RSUID[1] = timebuf[1]
            RSUID[2] = timebuf[2]
            RSUID[3] = timebuf[3]

            ret = self.INITIALISATION_rq(iMfd, RSUID, strUnixTime, 0, 0, "", 0, self.CALL_TIMEOUT)
            print(f"发送BST = {ret}")
            if ret != 0:
                continue
                
            ret = self.INITIALISATION_rs(iMfd, byref(ReturnStatus), byref(Profile), 
                                        byref(ApplicationList), Application, ObuConfiguration, 
                                        self.CALL_TIMEOUT)
            print(f"接收VST = {'成功' if ret == 0 else '失败'}")
            print(f"OBU ID= {self._bytes_to_hex(ObuConfiguration[:4])}")
            if ret == 0:
                found = 1
                break
                
        return found == 1

    def _bytes_to_hex(self, byte_arr):
        """字节数组转16进制字符串"""
        return ''.join(f'{b:02X}' for b in byte_arr)

    def SetMMI(self, fd, mode, did, set_mmi_para):
        """设置MMI参数
        Args:
            fd: 设备句柄
            mode: 模式
            did: 设备ID
            set_mmi_para: 要设置的参数
        Returns:
            bool: 是否成功
        """
        ret = self.SetMMI_rq(fd, mode, did, set_mmi_para, self.CALL_TIMEOUT)
        if ret != 0:
            return False
            
        return_status = c_int(0)
        ret = self.SetMMI_rs(fd, byref(c_int(did)), byref(return_status), self.CALL_TIMEOUT)
        return ret == 0 and return_status.value == 0

    def EventReport(self, fd, mode, did, event_type):
        """事件报告
        Args:
            fd: 设备句柄
            mode: 模式
            did: 设备ID
            event_type: 事件类型
        Returns:
            bool: 是否成功
        """
        ret = self.EVENT_REPORT_rq(fd, mode, did, event_type, self.CALL_TIMEOUT)
        return ret == 0

    def TransferChannel(self, fd, mode, did, channel_id, apdu_data):
        """透传通道操作
        Args:
            fd: 设备句柄
            mode: 模式
            did: 设备ID
            channel_id: 通道ID
            apdu_data: APDU指令数据
        Returns:
            tuple: (是否成功, 返回数据)
        """
        apdu_list = len(apdu_data)
        ret = self.TransferChannel_rq(fd, mode, did, channel_id, apdu_list, apdu_data, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        return_did = c_int(0)
        return_channel = c_int(0)
        return_apdu_list = c_int(0)
        return_status = c_int(0)
        return_data = (c_byte * 1024)()
        
        ret = self.TransferChannel_rs(fd, byref(return_did), byref(return_channel), 
                                    byref(return_apdu_list), return_data, 
                                    byref(return_status), self.CALL_TIMEOUT)
                                    
        if ret == 0 and return_status.value == 0:
            return (True, bytes(return_data[:return_apdu_list.value]))
        return (False, None)

    def GetSecure(self, fd, access_credential_op, mode, did, credentials, key_id, fid, offset, length):
        """安全获取数据
        Args:
            fd: 设备句柄
            access_credential_op: 访问凭证操作
            mode: 模式
            did: 设备ID
            credentials: 凭证数据
            key_id: 密钥ID
            fid: 文件ID
            offset: 偏移量
            length: 长度
        Returns:
            tuple: (是否成功, 文件数据)
        """
        rand_rsu = (c_byte * 16)()
        ret = self.GetSecure_rq(fd, access_credential_op, mode, did, credentials, 
                              key_id, fid, offset, length, rand_rsu, 
                              key_id, key_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        return_did = c_int(0)
        return_fid = c_int(0)
        return_length = c_int(0)
        file_data = (c_byte * 1024)()
        authenticator = (c_byte * 16)()
        return_status = c_int(0)
        
        ret = self.GetSecure_rs(fd, byref(return_did), byref(return_fid), 
                              byref(return_length), file_data, 
                              authenticator, byref(return_status), 
                              self.CALL_TIMEOUT)
                              
        if ret == 0 and return_status.value == 0:
            return (True, bytes(file_data[:return_length.value]))
        return (False, None)

    def Make_apdu(self, apdulist, strhex, apdu):
        """生成APDU指令
        Args:
            apdulist: 指令数量
            strhex: 16进制指令字符串
            apdu: 16进制指令字节数组
        """
        iLen = len(strhex) // 2
        byteSource = []
        if apdulist != 0:
            byteSource.extend(apdu[:apdulist])
            
        for i in range(iLen):
            byteSource.append(int(strhex[i*2:i*2+2], 16))
            
        apdulist = len(byteSource)
        apdu[:apdulist] = byteSource

    def PSAM_Channel(self, fd, psam_slot, apdu_list, apdu_data):
        """PSAM通道操作
        Args:
            fd: 设备句柄
            psam_slot: PSAM卡槽
            apdu_list: APDU指令数量
            apdu_data: APDU指令数据
        Returns:
            tuple: (是否成功, 返回数据)
        """
        ret = self.PSAM_CHANNEL_rq(fd, psam_slot, apdu_list, apdu_data, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        return_apdu_list = c_int(0)
        return_data = (c_byte * 1024)()
        ret = self.PSAM_CHANNEL_rs(fd, psam_slot, byref(return_apdu_list), return_data, self.CALL_TIMEOUT)
        
        if ret == 0:
            return (True, bytes(return_data[:return_apdu_list.value]))
        return (False, None)

    def SM4_Diversify(self, divisor, in_key):
        """SM4密钥分散
        Args:
            divisor: 分散因子
            in_key: 输入密钥
        Returns:
            bytes: 分散后的密钥
        """
        out_key = (c_byte * 16)()
        ret = self.SM4_Diversify_Run(divisor, in_key, out_key)
        if ret == 0:
            return bytes(out_key)
        return None

    def SM4_ECB(self, encrypt, in_data, key):
        """SM4 ECB模式加密/解密
        Args:
            encrypt: True为加密，False为解密
            in_data: 输入数据
            key: 密钥
        Returns:
            bytes: 处理后的数据
        """
        out_data = (c_byte * len(in_data))()
        ret = self.SM4_ECB_Run(1 if encrypt else 0, in_data, out_data, len(in_data), key)
        if ret == 0:
            return bytes(out_data)
        return None

    def SM4_CBC(self, iv, encrypt, in_data, key):
        """SM4 CBC模式加密/解密
        Args:
            iv: 初始化向量
            encrypt: True为加密，False为解密
            in_data: 输入数据
            key: 密钥
        Returns:
            bytes: 处理后的数据
        """
        out_data = (c_byte * len(in_data))()
        ret = self.SM4_CBC_Run(iv, 1 if encrypt else 0, in_data, out_data, len(in_data), key)
        if ret == 0:
            return bytes(out_data)
        return None

    def SM4_MAC(self, key, in_data, iv):
        """SM4 MAC计算
        Args:
            key: 密钥
            in_data: 输入数据
            iv: 初始化向量
        Returns:
            bytes: MAC值
        """
        mac = (c_byte * 16)()
        ret = self.SM4_MAC_Run(key, in_data, len(in_data), iv, mac)
        if ret == 0:
            return bytes(mac)
        return None

    def DES_CalcSingleMac(self, key, init_data, en_data):
        """DES单倍长MAC计算
        Args:
            key: 密钥
            init_data: 初始数据
            en_data: 加密数据
        Returns:
            bytes: MAC值
        """
        mac = (c_byte * 8)()
        ret = self.DES_CalcSingleMac(key, init_data, len(en_data), en_data, mac)
        if ret == 0:
            return bytes(mac)
        return None

    def DES_CalcTripleMac(self, key, init_data, en_data):
        """DES三倍长MAC计算
        Args:
            key: 密钥
            init_data: 初始数据
            en_data: 加密数据
        Returns:
            bytes: MAC值
        """
        mac = (c_byte * 8)()
        ret = self.DES_CalcTripleMac(key, init_data, len(en_data), en_data, mac)
        if ret == 0:
            return bytes(mac)
        return None

    def TripleDES(self, encrypt, mode, input_data, key):
        """3DES加密/解密
        Args:
            encrypt: True为加密，False为解密
            mode: 模式
            input_data: 输入数据
            key: 密钥
        Returns:
            bytes: 处理后的数据
        """
        output = (c_byte * len(input_data))()
        out_len = c_int(len(input_data))
        ret = self.DES_TripleDes(1 if encrypt else 0, mode, input_data, 
                               len(input_data), output, byref(out_len), 
                               key, len(key))
        if ret == 0:
            return bytes(output[:out_len.value])
        return None

    def Purchase_Consume(self, fd, psam_slot, amount, tac_key, consume_key):
        """消费交易处理
        Args:
            fd: 设备句柄
            psam_slot: PSAM卡槽
            amount: 交易金额(分)
            tac_key: TAC密钥
            consume_key: 消费密钥
        Returns:
            tuple: (是否成功, TAC值)
        """
        # 初始化交易参数
        purchase_data = (c_byte * 256)()
        tac = (c_byte * 4)()
        
        # 构造消费指令
        ret = self.PURCHASE_rq(fd, psam_slot, amount, tac_key, consume_key, 
                             purchase_data, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        # 处理消费响应
        return_amount = c_int(0)
        return_tac = (c_byte * 4)()
        return_status = c_int(0)
        
        ret = self.PURCHASE_rs(fd, psam_slot, byref(return_amount), 
                             return_tac, byref(return_status), 
                             self.CALL_TIMEOUT)
                             
        if ret == 0 and return_status.value == 0:
            return (True, bytes(return_tac))
        return (False, None)

    def GetVehicleInfo(self, fd, channel_id, key):
        """获取车辆信息
        Args:
            fd: 设备句柄
            channel_id: 通道ID
            key: 解密密钥
        Returns:
            tuple: (是否成功, 车辆信息结构体)
        """
        # 请求车辆信息
        ret = self.GET_VEHICLE_INFO_rq(fd, channel_id, key, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        # 接收车辆信息
        vehicle_info = TVehicleFileInfo()
        return_status = c_int(0)
        
        ret = self.GET_VEHICLE_INFO_rs(fd, channel_id, byref(vehicle_info), 
                                     byref(return_status), self.CALL_TIMEOUT)
                                     
        if ret == 0 and return_status.value == 0:
            return (True, vehicle_info)
        return (False, None)

    def GetSystemInfo(self, fd, channel_id):
        """获取系统信息
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 系统信息结构体)
        """
        # 请求系统信息
        ret = self.GET_SYSTEM_INFO_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        # 接收系统信息
        system_info = TSystemFileInfo()
        return_status = c_int(0)
        
        ret = self.GET_SYSTEM_INFO_rs(fd, channel_id, byref(system_info), 
                                    byref(return_status), self.CALL_TIMEOUT)
                                    
        if ret == 0 and return_status.value == 0:
            return (True, system_info)
        return (False, None)

    def Get0015FileInfo(self, fd, channel_id, key):
        """获取0015文件信息
        Args:
            fd: 设备句柄
            channel_id: 通道ID
            key: 解密密钥
        Returns:
            tuple: (是否成功, 0015文件结构体)
        """
        # 请求0015文件信息
        ret = self.GET_0015_FILE_rq(fd, channel_id, key, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        # 接收0015文件信息
        file_info = T0015FileInfo()
        return_status = c_int(0)
        
        ret = self.GET_0015_FILE_rs(fd, channel_id, byref(file_info), 
                                  byref(return_status), self.CALL_TIMEOUT)
                                  
        if ret == 0 and return_status.value == 0:
            return (True, file_info)
        return (False, None)

    def GetCardInfo(self, fd, channel_id):
        """获取卡片信息
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 卡片信息字典)
        """
        card_info = {}
        ret = self.GET_CARD_INFO_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        card_type = c_int(0)
        card_status = c_int(0)
        card_id = (c_byte * 16)()
        return_status = c_int(0)
        
        ret = self.GET_CARD_INFO_rs(fd, channel_id, byref(card_type), 
                                  byref(card_status), card_id, 
                                  byref(return_status), self.CALL_TIMEOUT)
                                  
        if ret == 0 and return_status.value == 0:
            card_info['type'] = card_type.value
            card_info['status'] = card_status.value
            card_info['id'] = self._bytes_to_hex(card_id[:8])
            return (True, card_info)
        return (False, None)

    def GetBalance(self, fd, channel_id, key):
        """获取卡片余额
        Args:
            fd: 设备句柄
            channel_id: 通道ID
            key: 解密密钥
        Returns:
            tuple: (是否成功, 余额(分))
        """
        ret = self.GET_BALANCE_rq(fd, channel_id, key, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        balance = c_int(0)
        return_status = c_int(0)
        
        ret = self.GET_BALANCE_rs(fd, channel_id, byref(balance), 
                                byref(return_status), self.CALL_TIMEOUT)
                                
        if ret == 0 and return_status.value == 0:
            return (True, balance.value)
        return (False, None)

    def GetTransactionLog(self, fd, channel_id, key, log_index):
        """获取交易日志
        Args:
            fd: 设备句柄
            channel_id: 通道ID
            key: 解密密钥
            log_index: 日志索引
        Returns:
            tuple: (是否成功, 交易日志字典)
        """
        ret = self.GET_TRANS_LOG_rq(fd, channel_id, key, log_index, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        trans_log = {}
        trans_type = c_int(0)
        trans_amount = c_int(0)
        trans_time = (c_byte * 4)()
        terminal_id = (c_byte * 6)()
        tac = (c_byte * 4)()
        return_status = c_int(0)
        
        ret = self.GET_TRANS_LOG_rs(fd, channel_id, byref(trans_type), 
                                  byref(trans_amount), trans_time, 
                                  terminal_id, tac, byref(return_status), 
                                  self.CALL_TIMEOUT)
                                  
        if ret == 0 and return_status.value == 0:
            trans_log['type'] = trans_type.value
            trans_log['amount'] = trans_amount.value
            trans_log['time'] = self._bytes_to_bcd(trans_time)
            trans_log['terminal_id'] = self._bytes_to_hex(terminal_id)
            trans_log['tac'] = self._bytes_to_hex(tac)
            return (True, trans_log)
        return (False, None)

    def _bytes_to_bcd(self, byte_arr):
        """字节数组转BCD码
        Args:
            byte_arr: 字节数组
        Returns:
            str: BCD字符串
        """
        return ''.join(f'{b:02d}' for b in byte_arr)

    def GetCardSerialNumber(self, fd, channel_id):
        """获取卡片序列号
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 卡片序列号)
        """
        ret = self.GET_CARD_SERIAL_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        serial_number = (c_byte * 10)()
        return_status = c_int(0)
        
        ret = self.GET_CARD_SERIAL_rs(fd, channel_id, serial_number, 
                                    byref(return_status), self.CALL_TIMEOUT)
                                    
        if ret == 0 and return_status.value == 0:
            return (True, self._bytes_to_hex(serial_number))
        return (False, None)

    def GetCardVersion(self, fd, channel_id):
        """获取卡片版本号
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 卡片版本号)
        """
        ret = self.GET_CARD_VERSION_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        version = (c_byte * 2)()
        return_status = c_int(0)
        
        ret = self.GET_CARD_VERSION_rs(fd, channel_id, version, 
                                     byref(return_status), self.CALL_TIMEOUT)
                                     
        if ret == 0 and return_status.value == 0:
            return (True, self._bytes_to_hex(version))
        return (False, None)

    def GetCardManufacturer(self, fd, channel_id):
        """获取卡片制造商
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 制造商代码)
        """
        ret = self.GET_CARD_MANUFACTURER_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        manufacturer = (c_byte * 4)()
        return_status = c_int(0)
        
        ret = self.GET_CARD_MANUFACTURER_rs(fd, channel_id, manufacturer, 
                                          byref(return_status), self.CALL_TIMEOUT)
                                          
        if ret == 0 and return_status.value == 0:
            return (True, self._bytes_to_hex(manufacturer))
        return (False, None)

    def GetCardProductionDate(self, fd, channel_id):
        """获取卡片生产日期
        Args:
            fd: 设备句柄
            channel_id: 通道ID
        Returns:
            tuple: (是否成功, 生产日期字符串)
        """
        ret = self.GET_CARD_DATE_rq(fd, channel_id, self.CALL_TIMEOUT)
        if ret != 0:
            return (False, None)
            
        date = (c_byte * 4)()
        return_status = c_int(0)
        
        ret = self.GET_CARD_DATE_rs(fd, channel_id, date, 
                                  byref(return_status), self.CALL_TIMEOUT)
                                  
        if ret == 0 and return_status.value == 0:
            return (True, self._bytes_to_bcd(date))
        return (False, None)

if __name__ == "__main__":
    """测试代码"""
    try:
        m600 = M600t()
        print("M600t初始化完成")
    except Exception as e:
        print(f"初始化出错: {str(e)}")